home *** CD-ROM | disk | FTP | other *** search
/ The Programmer Disk / The Programmer Disk (Microforum).iso / xpro / c4 / pro17 / no.c < prev    next >
C/C++ Source or Header  |  1991-06-04  |  6KB  |  235 lines

  1. /*
  2.  
  3.        Program title:   no.c
  4.  
  5.        Purpose:         Rewrite of a classic utility for those who still
  6.                         use the DOS command-line interface ...
  7.  
  8.                         Excludes filespec from a command-line operation.
  9.                         e.g. NO *.BAT ERASE *.* would delete everything
  10.                         EXCEPT batch files in current directory.
  11.  
  12.        Author:          Michael Salera (idea by Charles Petzold)
  13.       Release:         P.D. / shareware (see no.doc)
  14.  
  15. */
  16.  
  17.  
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <dir.h>                    /* non-standard headers */
  21. #include <dos.h>                    /* os2.h ?? */
  22. #include <errno.h>
  23. #include <assert.h>
  24. #include <string.h>
  25. #include <process.h>
  26. #include "lists.h"                    /* linked-list data structures */
  27.  
  28. #define FNAME_STR 13                /* 13-byte string for filename */
  29. #define NDEBUG
  30.  
  31. /*
  32.     #define NDEBUG  for "no debugging" if this were to become
  33.     a finished product.  Squelches all assert(expression) macros.
  34.  
  35.     Compiler details - this was compiled & linked using Borland's
  36.     Turbo C++ 1.0 with absolutely no C++ extensions, so that MSC 5.1+
  37.     should also compile this with few problems.
  38.  
  39.     The whole reason I bothered to write this utility was to try to port
  40.     it to OS/2 1.3, which I now work with.  However, since I have little
  41.     documentation on the IBM C/2 compiler, this program still needs to
  42.     replace DOS-specific code with OS/2 functions.
  43. */
  44.  
  45.  
  46. /*
  47.     The command line args are everything to this program:
  48.     argv[1]                argv[2]            argv[3]
  49.     *.CMD                DEL                *.*
  50.  
  51.     what to exclude
  52.                         actual command
  53.                                         command parms.
  54.  
  55.     1.    Basically argv[1] must be expanded from its wildcard state
  56.         (*.CMD) into a linked list of actual filespecs to be hidden.
  57.         findfirst() / DosFindFirst() takes care of this.
  58.  
  59.     2.      Function hide_diskfile(const char* path) will successively
  60.         hide each file.
  61.  
  62.     3.    Once the hidden attribute is set, then the next step is to
  63.         spawnl( P_WAIT mode!... ) the command and make sure it
  64.         gets its parameters.
  65.  
  66.     4.    Function un_hide_diskfile(const char* path) takes the old list
  67.         and, as one might guess, resets the archive attribute.
  68.  
  69.     5.    Free the space allocated for the list and exit.
  70. */
  71.  
  72.  
  73.  
  74. /*                       P R O T O T Y P E S  */
  75.  
  76. LINK expand_wc(const char *wildcard);   /* returns pointer to newly created list */
  77. void hide_diskfile(const char *path);
  78. void un_hide_diskfile(const char *path);
  79.  
  80. /*     returns how many were in list for diagnostic or statistical purposes,
  81.     "NO excluded 5 files" ... */
  82. int cleanup(LINK head);
  83.  
  84.  
  85.  
  86. /*                       D E F I N I T I O N S */
  87.  
  88. /*    returns pointer to newly created list - or NULL if no file matches
  89.     the wildcard spec. given */
  90. LINK expand_wc(const char *wildcard)    
  91. {
  92.     LINK head, tail;
  93.     struct ffblk dirinfo;
  94.     int done;
  95.  
  96.     /*    findfirst() is a DOS-SPECIFIC function */
  97.     if (done = findfirst(wildcard, &dirinfo, FA_ARCH))
  98.         return (NULL);                /* not even one match ! */
  99.  
  100.      /* list is empty - initialize pointers to new node */
  101.     head = tail = (LINK) malloc(sizeof(ELEMENT));
  102.  
  103.     while (!done)  {
  104.         /* copy filename to info field */
  105.         tail -> info = (DATA) malloc(FNAME_STR);
  106.         strcpy(tail -> info, dirinfo.ff_name);
  107.  
  108.         /*    findnext() is a DOS-SPECIFIC function */
  109.         if (done = findnext(&dirinfo))  {    /* no more matches - end list */
  110.             tail -> next = NULL;
  111.             }
  112.  
  113.         /* if more filenames then create link - done == 0 on success */
  114.         else  {
  115.             tail -> next = (LINK) malloc(sizeof(ELEMENT));
  116.             tail = tail -> next;
  117.             }
  118.         }
  119.  
  120.     assert(done); assert(head != NULL);
  121.     return (head);
  122. }
  123.  
  124.  
  125. /*    _chmod() is a DOS-SPECIFIC function */
  126. void hide_diskfile(const char *path)
  127. {
  128.     int errcode;
  129.  
  130.     errcode = _chmod(path, 1, FA_HIDDEN);
  131.     assert(errcode == FA_HIDDEN);
  132. }
  133.  
  134.  
  135. /*    _chmod() is a DOS-SPECIFIC function */
  136. void un_hide_diskfile(const char *path)
  137. {
  138.     int errcode;
  139.  
  140.     errcode = _chmod(path, 1, FA_ARCH);
  141.     assert(errcode == FA_ARCH);
  142. }
  143.  
  144.  
  145. /*     returns how many were in list for diagnostic or statistical purposes,
  146.     "NO excluded 5 files ..." */
  147. int cleanup(LINK head)
  148. {
  149.     LINK temp_ptr;
  150.     int num_in_list = 0;
  151.  
  152.     while (head)  {
  153.         ++num_in_list;
  154.  
  155.         /* unlink first node from the list */
  156.         temp_ptr = head;
  157.         head = head -> next;
  158.  
  159.         /* start freeing nodes */
  160.         free(temp_ptr);
  161.         }
  162.  
  163.     return (num_in_list);
  164. }
  165.  
  166.  
  167.  
  168. /*                       P R O G R A M  B E G I N S */
  169.  
  170. int main(int argc, char *argv[])
  171. {
  172.     LINK head, trail_ptr;
  173.     const char *cmd_line_typo = "NO: usage is NO <filespec> <cmd> [<parms>]";
  174.     const char *file_typo = "NO: error in filespec - file(s) non existent";
  175.     char *path = "COMMAND.COM";
  176.     char *cmd_parms = "/c ";            /* would be "cmd /c" under OS/2 */
  177.     int num_hid;
  178.  
  179.     if ((argc < 3) || (argc > 4))  {    /* cmd.-line checkup */
  180.         fprintf(stderr, "%s\n\n", cmd_line_typo);
  181.         return (1);
  182.         }
  183.  
  184.     if ((head = expand_wc(argv[1])) == NULL)  {
  185.         fprintf(stderr, "%s\n\n", file_typo);
  186.         return (1);
  187.         }
  188.  
  189.     /*     Command-line args are OK, head now points to a list of files
  190.         to be hidden.  Now traverse list and hide each */
  191.     trail_ptr = head;
  192.     while (trail_ptr)  {
  193.         hide_diskfile(trail_ptr -> info);
  194.         trail_ptr = trail_ptr -> next;
  195.         }
  196.  
  197.     /*    Building the actual command line & exec child process.
  198.         all are preceded by "command /c" in case of internal "dir,"
  199.         "del," "type," etc. */
  200.     strcat(cmd_parms, argv[2]);        /* required */
  201.     if (argv[3] != NULL)  {
  202.         strcat(cmd_parms, " ");        /* add third parameter to spawn */
  203.         strcat(cmd_parms, argv[3]);
  204.         }
  205.  
  206.     if (spawnlp(P_WAIT, path, argv[0], cmd_parms, NULL) == -1)
  207.         switch (errno)  {
  208.             case EINVAL:    fprintf(stderr, "Invalid argument.");
  209.                         break;
  210.  
  211.             case ENOENT:    fprintf(stderr, "Path or file name not found.");
  212.                         break;
  213.  
  214.             case ENOEXEC:    fprintf(stderr, "Exec format error.");
  215.                         break;
  216.  
  217.             case ENOMEM:    fprintf(stderr, "Not enough core memory.");
  218.                         break;
  219.  
  220.             default:        fprintf(stderr, "Error number: %d", errno);
  221.             }
  222.  
  223.     /*    Now traverse & un-hide */
  224.     trail_ptr = head;
  225.     while (trail_ptr)  {
  226.         un_hide_diskfile(trail_ptr -> info);
  227.         trail_ptr = trail_ptr -> next;
  228.         }  
  229.  
  230.     num_hid = cleanup(head);            /* let's be neat! */
  231.     fprintf(stdout, "\nNO excluded %d files from command.\n", num_hid);
  232.  
  233.     return (0);
  234. }
  235.